/**
 * 1.索引底层实现原理
 *      1.mysql底层索引采用b+树的结构
 *      2.b+树的特性：数据存放在叶子节点上，非叶子节点存放的都是索引，叶子节点本身根据数据的大小通过链表顺序链接
 *      3.查找时会通过非叶子节点的索引直接查询到叶子节点上，定位出数据，每次都会走一条高度的路径
 *      4.叶子节点间由顺序链表连接，增加了区间查找的访问速度
 *      5.B+树会自动分裂，比二叉树红黑树等好的地方是减少了磁盘查询的次数
 *      6.为什么不用b树要b+树：b+树叶子节点每个节点之间有双向链表连接，更适合排序和范围查询，b+树的非叶子节点存储的只有索引，而b树的叶子节点存储索引和数据，会
 *        造成分列的次数更多，因为每一页的大小是16k，如果存储的数据多了，就会分裂，但是b+树只存储索引，索引存储的数据少，分列次数少
 *
 * 2.数据库三大范式
 *      1.第一范式：列不可再分，确保每一列的原子性，两列属性如果差不多，尽量合并属性成一列，不产生冗余数据
 *      2.第二范式：基于第一范式，保证表中的每一行可以被唯一区分，一般加一个主键列
 *      3.第三范式：基于第二范式，每个属性都跟主键有直接关系而不是间接关系，比如（学号，姓名，所在院校，院校地址），学号和姓名和所在院校是直接关系，而院校地址不是，所以最好拆分成两张表
 *
 * 3.innodb和myisam的区别：
 *      1.事务：支持事务和不支持
 *      2.外键：支持外键和不支持
 *      3.聚集索引：聚集索引和非聚集索引
 *          1.innodb：索引和数据是放到同一个文件里面的，在叶子节点中同时存放索引和数据
 *          2.myisam：索引和数据是在不同的文件中的，b+树中叶子节点存储索引和指向文件的指针
 *      4.行数：不保持行数和保存行数
 *      5.全文索引：不支持全文索引和支持全文索引
 *      7.锁：支持表，行级锁和只支持表级锁
 *      8.主键：必须要主键（没设置也会自动添加），可以没有
 *
 * 4.innodb和myisam的场景：
 *      1.innodb：事务，插入更新频繁
 *      2.mysiam：无事务，查询频繁，count频繁
 *
 * 5.事务隔离级别：
 *      1.读未提交：一个事务还没提交时，它做的变更就能被别的事务看到
 *          脏读  A读取到了B未提交的数据
 *      2.读提交：一个事务提交之后，它做的变更才会被其他事务看到
 *          不可重复读  A读取数据，B更新了数据，A又读取了数据，两次读取到的不一样
 *      3.可重复读：一个事务执行过程中看到的数据，总是跟这个事务在启动时看到的数据是一致的
 *          幻读  A查询数据，B插入数据，A重新查询，两次不一样
 *      4.串行化：不存在问题，但降低吞吐量
 * 8.主从复制、读写分离
 *      1.为什么
 *          1.提高数据库并发性能
 *          2.高可用，数据防丢失
 *      2.原理
 *          1.master节点的增删改操作都存到bin-log中
 *          2.通过io线程发送给slave
 *          3.slave将bin-log内容写入relay-log中
 *          4.sql线程读取relay-log，并且执行增删改操作
 * 9.mysql的日志
 *      1.binlog
 *          1.用于记录数据库执行的增删改操作，一般用于主从复制或者给mq用于同步数据
 *      2.undolog
 *          1.用于回滚和多版本并发控制
 *          2.比如insert一条数据，Undolog会记录一条对应的delete日志，执行失败了就回滚，返回前一个版本就行
 *      3.redolog
 *          1.mysql修改数据的基本单位为页，先把页数据从磁盘中查出来，存到内存中再作修改
 *          2.而内存中修改完数据之后，还没来的及落到磁盘就挂了，那数据不就没了
 *          3.所以引入redolog，记录做了什么修改，以便恢复
 *          4.一般用于宕机恢复
 * 10.分库分表：
 *      1.垂直分库：产生分布式事务问题
 *          1.如果单论mysql分库，一般依据表的业务不同，或者整体项目不同将表拆分到不同的库里面去
 *          2.库的概念其实可以高于mysql的库，还有mongo，es，hadoop等等，我们设计的计算库为mongo，查询库为es，大数据存储库为impala，大数据分析库为doris
 *      2.水平分库：用户请求量太大，单服务器磁盘容量不够
 *          1.水平分库其实是要解决并发量的问题，单库部署在一台服务器上，挡不住并发，一般用hash或者取模将一个库中的数据拆分到不同的库中，一般不怎么用这个
 *      3.垂直分表
 *          1.其实就是将一张表的数据分到不同的表上，之间用Id进行关联，用以解决单行数据过大的问题，如果单行数据过大，会造成数据库缓存或者读io的瓶颈
 *      4.水平分表：单表数据量过大
 *          1.水平分表，以某个字段为依据，将数据拆分到不同的表中去，分表后的每个表结构是一样的。现在其实也不用分表了，对于巨大容量的表，曾经接触过一张4亿条数据的
 *            表，我们选择用大数据分析库doris或者阿里云数据分析库mysql2.0进行存储，存在单张表上，以时间为分区，id做分桶
 *      5.框架：sharing jdbc ， mycat等，以前有用sharding jdbc做水平分表，但是代码耦合有点大，框架里面已经做好了分表存储，增删改查等策略了
 * 11.update user set name = 'aaa' where id = 5 这条sql语句在mysql中如何执行?
 *      1.进入解析器，解析sql语法
 *      2.进入优化器，针对sql语句生成查询路径，选择最优查询路径，生成执行计划
 *      3.进入执行器，把执行计划交给存储引擎去执行。
 *      4.假定是innodb存储引擎
 *          1.查询缓冲池，若是没有数据，则将包含id=5的页数据从磁盘加载到缓冲池
 *              1.缓冲池（buffer pool）：会缓存一些从磁盘中加载出来的页数据，如果缓冲池中已有数据，则不会去查询磁盘。
 *          2.将旧数据行写入undo日志文件中，用作数据回滚name = 'xx'
 *              1.undo日志为了支持事务的回滚和多版本并发控制MVCC，记录的是旧的值
 *          3.更新缓冲池中的数据，name='aa'
 *          4.写入redo日志缓存
 *              1.redolog：内存中的一个缓冲区，记录的是你对这行数据的操作，用来在mysql突然宕机的时候，来恢复更新过的数据的。因为mysql数据库宕机，
 *                缓冲池中的数据就会丢失，此时磁盘数据还未更新，那么数据丢失了。
 *          5.准备提交事务，将redo日志刷入磁盘或者os cache，建议刷入磁盘来保证数据不丢失
 *          6.准备提交事务，将Binlog日志写入磁盘
 *          7.把本次更新对应的binlog文件名称和这次更新的binlog日志文件里的位置，写入到redolog日志文件里面去，同时在redolog里写入一个commit标记
 *              1.为保证binlog的写入和redolog的写入保持一致性，引入了mysql内部的XA事务提交规范，也就是两阶段协议
 *              2.第一阶段：innodb prepare，sql执行成功,redo日志会先进行记录，但是未提交commit，进入prepare
 *              3.第二阶段：binlog持久化落入磁盘，然后开始commit，并且在redo日志中记录事务的commit
 *          8.Io线程异步将缓冲池数据刷到磁盘
 * 12.事务的传播机制有几种，分别用在什么场景？（在service1中调用service2方法）
 *      1.支持事务
 *          1.如果存在事务则加入，不存在则创建（默认的），两个服务都有写操作，只要一个发生异常就都回滚
 *          2.如果当前存在事务，则加入该事务；不存在则直接执行，适合查询方法。这种行为中如果service1启动了一个事务，service2能加入该事务，从而读取到service1当前修改的数据，
 *              否则会由于事务未提交无法读取service1中修改的数据（隔离级别大于读未提交）
 *          3.强制要求当前存在一个事务，不存在则抛出异常，service2需要事务支持，但自身又不想管理事务的提交或回滚
 *          4.不管当前是否存在事务，必定创建一个事务，如果当前存在事务，则这个事务会被挂起，service2的事务失败不想影响到service1
 *          5.如果不存在，则创建新的；如果存在，则在当前事务的一个嵌套事务中执行，嵌套的关系是外层事务的子事务，子事务执行，外层事务不会被挂起，子事务和外层事务共有事务状态，
 *           将一个大事务分解为多个小事务执行，根据小事务的执行状态决定大事务的执行流程
 *      2.不支持事务
 *          1.不支持当前事务，若存在则挂起
 *          2.永远不使用事务，存在则抛出异常
 * 13.transcational失效的可能
 *      1.函数必须是public的，否则事务不生效
 *      2.数据库引擎要支持事务，如果是Mysql，注意表要使用支持事务的引擎，比如innodb，如果是myisam，事务不生效
 *      3.异常在catch后必须抛出，否则不会进行回滚
 *      4.加上rollbackFor=Exception.class后，运行时异常才会被回滚
 * 14.mysql性能调优
 *      1.影响性能的情况，不建议使用的情况：
 *          1.自定义函数：查询的数据使用自定义函数，查多少条使用多少次，影响性能
 *          2.group_concat：字符串聚合函数，会影响sql响应时间，谨慎使用
 *          3.text字段：text字段会消耗大量Io，谨慎使用
 *          4.内联子查询：select id,(select rule_name from member_rule limit 1) as rule_name from table，返回多少数据查询多少次
 *          5.不建议使用Left_join，即使用on做条件过滤，一些情况也不走索引
 *          6.不建议使用子查询，因为mysql的优化器对子查询处理的能力比较弱，可以改成inner_join
 *          7.group by和order by 后面的列最好要有索引，可以使排序更快点
 *          8.Limit谨慎使用，分页查询时，m越大即页数越多查询越慢，这种查询应该先取出主键然后用join关联查询
 *              select * from tableA a inner join (select id from tableB limit 10,10) b on a.id = b.id
 *      2.索引失效的情况
 *          1.where的条件后面，是不能进行任何运算的，或者使用函数的，会导致索引失效
 *          2.数据类型出现隐式转化，int类型的字段传varchar是可以走索引的，varchar类型传int不走索引
 *          3.Not in  ，<> 不走索引
 *          4.使用is null或者is not null的时候，索引不一定生效
 *              1.null值在b+树中的存储是最左边的，因为mysql默认null值是列中最小的值
 *              2.如果是is not null 就会走那个字段的索引，从小到大查询直到不为Null，其实是走了索引
 *              3.使不使用索引的依据到底是什么？mysql会计算出要扫描的二级索引的条数或者要执行回表的次数，计算成本，
 *                  如果这个条数占整个记录条数的比例特别大，那么就趋向于使用全表扫描执行查询，否则趋向于使用这个索引执行查询
 *          5.or的条件如果都走索引的话，才走索引，只有一个走索引，就会导致索引失效
 *          6.组合索引，要遵从最左原则，如果最左边的没用到索引，就会失效
 *          7.like 以%开头的才走索引，不以%开头的不走
 *          8.mysql如果执行一条sql语句执行计划和成本计算发现，走全表扫描比走索引更加快，就会不走索引
 *      3.使用索引
 *          1.聚簇索引，存储了id值和其它字段的值的一个索引，mysql建表之后就会创建这个索引
 *          2.回表：比如建立了一个name的索引，那么这个索引就会建成id和name的映射，在b+树中，如果想要查询name，则先查出id，再根据id去聚簇索引中查询出数据
 *          3.覆盖索引（一种优化手段，不是一种索引结构）
 *              1.覆盖索引是指，索引上的信息足够满足查询请求，不需要再回到主键上去取数据
 *              2.比如select * from table where name = "xx" 一般不走覆盖索引，因为使用了name索引查询出来数据后还得回表
 *          4.联合索引
 *              1.比如根据名称查询库存，如果只建立了名称的索引，那想查询到库存还得回表一次
 *          5.最左原则
 *              1.b+树中存储联合索引的结构是，比如建立了a和b的联合索引，那么b+树底层会以a做为索引，如果a的值相等，则才以b作为索引
 *              2.索引如果查询的时候不先查A，直接查b，是不走联合索引的
 *              3.Mysql会从联合索引的最左边开始匹配索引
 *          6.索引下推（mysql官方优化的一点）
 *              1.5.6以前在where条件中，一定是从最左边的条件开始查询，再回表再匹配下一个条件
 *              2.5.6后引入索引下推，会先去计算可能用到的索引，然后找到最优的走索引的方式，减少回表次数
 *          7.前缀索引
 *              1.比如邮箱 www.等字段，可以建立前缀索引，提高字符串的遍历，提高查询速度，但是前缀索引必定会回表，因为不知道前缀是什么
 *          8.全文索引
 *      4.explain
 *          1.字段
 *              1.select_type:查询类型,union，simple等等
 *              2.table:显示访问哪张表，可能不是真的表，是简称，或者第几步执行的结果
 *              3.type:表的访问类型
 *                  1.ALL:mysql会遍历全表以找到行
 *                  2.index：遍历索引树
 *                  3.range：只检索给定范围的行，使用一个索引来选择行
 *                  4.ref：表示上述表的连接匹配条件，即哪些列或者常量被用于查询索引树上的值
 *                  5.eq_ref: 类似ref，区别就在使用的索引是唯一索引，对于每个索引键值，表中只有一条记录匹配，简单来说，
 *                    就是多表连接中使用primary key或者 unique key作为关联条件
 *                  6.const、system: 当MySQL对查询某部分进行优化，并转换为一个常量时，使用这些类型访问。如将主键置于where列表中，
 *                    MySQL就能将该查询转换为一个常量，system是const类型的特例，当查询的表只有一行的情况下，使用system
 *                  7.NULL: MySQL在优化过程中分解语句，执行时甚至不用访问表或索引，例如从一个索引列里选取最小值可以通过单独索引查找完成。
 *              4.possible_key：mysql查询可能会用到的索引
 *              5.key：实际使用的索引
 *              6.key_len：索引字段的长度，key_len显示的值为索引字段的最大可能长度
 *              7.ref：列与索引的比较，表示上述表的连接匹配条件，即哪些列或常量被用于查找索引列上的值
 *              8.rows：mysql查询扫描的行数，这个行数并不是绝对准确的
 *              9.filtered：按表条件过滤的行百分比
 *              10.Extra：执行情况的描述和说明
 *                  1.Using where:不用读取表中所有信息，仅通过索引就可以获取所需数据，这发生在对表的全部的请求列都是同一个索引的部分的时候，
 *                    表示mysql服务器将在存储引擎检索行后再进行过滤
 *                  2.Using temporary：表示MySQL需要使用临时表来存储结果集，常见于排序和分组查询，常见 group by ; order by
 *                  3.Using filesort：当Query中包含 order by 操作，而且无法利用索引完成的排序操作称为“文件排序”，一种快排
 *                  4.Using join buffer：改值强调了在获取连接条件时没有使用索引，并且需要连接缓冲区来存储中间结果。如果出现了这个值，那应该注意，
 *                    根据查询的具体情况可能需要添加索引来改进能。
 *                  5.Impossible where：这个值强调了where语句会导致没有符合条件的行（通过收集统计信息不可能存在结果）。
 *                  6.Select tables optimized away：这个值意味着仅通过使用索引，优化器可能仅从聚合函数结果中返回一行
 *                  7.No tables used：Query语句中使用from dual 或不含任何from子句
 *      5.分库分表分区
 *      6.集群，主从复制，读写分离，高可用
 *      7.服务端优化：
 *          1.设置多个buffer_pool，可以减少并发访问加锁的压力
 *              buffer_pool内存大小为总内存的50%左右即可
 *              buffer_pool的数量跟内存和chunk有关，chunk是buffer_pool的组成，(chunk大小 * buffer_pool数量)*倍数
 * 15.MVCC多版本并发控制
 *      1.MVCC是多版本并发控制，
 *          1.在读提交，可重复读的级别下，会有多版本并发控制，每个事务都会有一个事务id
 *          2.在表中的每一行，都有两个隐藏列，一个是记录这个事务的版本id，就这个事务id，一个是一个指针，每次都这行数据有改动的时候，
 *          都会记录到undolog里面，而这个指针就是指向undolog的，undolog每次记录回滚都也有一个指针，对应上就可以进行数据的回滚
 * 16.mysql如何处理亿级数据
 *      1.mysql调优
 *      2.分库分表
 *      3.mysql分区技术
 *      4.数据库集群
 *      5.引入大数据组件
 * 17.内连接查询 (select * from a join b on a.id = b.id) 与 关联查询 (select * from a , b where a.id = b.id)的区别
 *      1.on会更快点，where是在数据都查询出来的时候才进行匹配筛选，而On是在联表的时候进行过滤
 *      2.如果where中有条件的话，on是会先查询出这个条件再关联，而where是先关联再通过条件过滤
 * 18.MVCC
 *      1.两个隐式字段
 *          1.DB_TRX_ID:最近一次的事务ID，
 *          2.DB_ROLL_PTR：回滚指针，指向这条记录的上一个版本
 *      2.Undo日志
 *          1.insert undo log：在Insert的时候产生的Undo日志，只有事务回滚时需要，并在事务提交后可以被立即丢弃
 *          2.update undo log：在update的时候产生的Undo日志，不仅在事务回滚的时候需要，在快照读的时候也需要；所以不能随便删除，只有在快速读和
 *            事务回滚不涉及该日志的时候，对应日志才会被purge线程统一删除
 *          3.purge的主要任务是将数据库中已经 mark del 的数据删除，另外也会批量回收undo pages
 *      3.readView
 *          1.读未提交和串行化是不需要用到readView的
 *          2.读提交和可重复读是通过版本控制完成的，核心逻辑是判断所有版本中哪个版本是当前事务可见的处理，所以增加了readView设计，readView中主要
 *            记录了哪些活跃的独写事务，把他们的事务ID放到一个列表中
 *          3.查询版本链的时候，如果trx_id比readView列表的最小id还小，说明，已经提交了，可以被当前事务访问；如果trx_id大于最大的id，表明生成该
 *            版本的事务在readView之后生成，所以该版本不可以被当前事务访问；如果在之间，那需要判断一下trx_id是否在里面，如果在说明当前还是活跃的，
 *            不可以访问，不在就可以访问
 *          4.在读提交和可重复读的场景下，readView生成的时机不同
 *              1.读提交：每次查询都会生成一个实时的readView，记录当前的活跃事务，做到保证每次提交后的数据都是处于当前的可见状态
 *              2.可重复读：第一次查询的时候生成当前的readView，并且当前的readView会一直沿用到当前的事务提交，以此来保证可重复读
 * 19.mysql执行delete删除是否真的删除了？
 *      1.其实删除之后，空间是没有变化的，类似一种逻辑删除，隐藏的deleted_flag字段会变为1
 *      2.如果下次再添加一行数据，那么这行数据就会添加到被删除的那一行上，这种叫行记录复用
 *      3.数据页也会被逻辑删除，如果一张表被删除的数据多了，就不得不增加其它的数据页来存储，会产生数据空洞问题，影响查询效率
 *      4.用optimize table t 重建表来解决这个问题
 * 20.buffer pool（缓冲池）
 *      1.配置缓冲池大小：默认128M，一般16核32g的机器，配置2g
 *      2.结构：
 *          1.描述数据：缓存页的大小，信息等
 *          2.缓存页：16K，加载到缓冲池中，为一个b+树叶子节点的大小
 *          3.free链表：每个节点就是一个空闲的缓存页的描述数据块地址，当存入一个缓存页，则删除一个free链表节点
 *          4.flush链表：记录缓冲池中被修改过的缓存页，在flush刷入磁盘的时候会从flush链表中取出缓存页
 *          5.LRU算法淘汰缓存：冷热数据分离法，LRU链表中分为热数据，在链表头N个节点，冷数据在链表末尾N个节点，如果是预读的数据是放到冷链表的头部，
 *            从存储引擎查出来数据并且1s内有修改数据的才会放到热数据的头部
 * 21.mysql如何解决幻读：
 *      1.通过多版本并发控制mvcc的readview机制，保证了非当前读下时，不会出现幻读问题
 *      2.通过next-key lock 保证了当前读下不会出现幻读问题
 *          1.next-key lock 是由record lock（行锁），grap lock（间隙锁）组成，在当前事务要对数据做查询更新插入的时候，就会进行next-key加锁
 *            保证当前事务下不会出现幻读问题
 *          2.间隙锁是对mysql的一段数据进行加索，加在索引之间，为前开后闭的
 * 22.b+树一千万数据要多少次io
 *      1.假定一行数据的大小为1k的话，B+树高度为2的话能存进2万的数据，高度为3的话能存近2000万的数据，需要三次io。计算方式其实是b+树的每一个节点是一个页，
 *        存储16k，也就是叶子结点是16条数据。然后非叶子结点存储的是主键和指针，主键bigint8个字节，指针6个字节，然后通过单个节点的计算，得出上述结论。
 *        如果还走二级索引的话，就可能需要多一倍的io，还得再计算一遍
 * 23.*索引下推
 *      1.索引下推是数据库检索数据过程中为减少回表次数而做的优化
 *      2.索引条件下推优化（Index Condition Pushdown (ICP) ）是MySQL5.6添加的，用于优化数据查询
 *      3.一条sql语句执行会先经过MYSQL服务器 再到 存储引擎，存储引擎检索出数据之后再将数据返回给MYSQL服务器，MYSQL服务器再对数据进行筛选
 *      4.例如：select * from t1 where name = ‘zhangsan’ and age = 10，做了name和age的联合索引
 *          1.没有索引下推之前：执行引擎会将name = 'zhangsan'的数据全部查询到mysql的server层，再回表，查询age = 10的数据
 *          2.有索引下推：server会将条件传给执行引擎，执行引擎查询数据并过滤，最后返回给server
 * @author
 * @created 2022/1/6 20:19
 */
public class Mysql {
}
